package br.com.timecardforpeon.sqlite;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import br.com.timecardforpeon.R;
import br.com.timecardforpeon.domain.Domain;
import br.com.timecardforpeon.exception.TimeCardException;

public abstract class BasicDao<T extends Domain> {

	private static final String GET_BY_ID_QUERY = "select * from %s where id = ?";
	protected Context context;
	protected TimeCard4PeonSQLiteOpenHelper dbHelper;

	public BasicDao(Context context) {
		this.context = context;
		this.dbHelper = new TimeCard4PeonSQLiteOpenHelper(context);
	}

	protected abstract T cursorToDomain(Cursor cursor) throws Exception;

	public T getById(T domain) {

		try {
			
			return this.executeUniqueResult(String.format(GET_BY_ID_QUERY, domain.getTableName()),
					"" + domain.getId());
		}
		catch (Exception e) {
			Log.e("timeCard4Peon", "Exception getById", e);
		}
		
		return null;
	}

	public T create(T domain) throws TimeCardException {

		SQLiteDatabase database = this.dbHelper.getWritableDatabase();
		long id = database.insert(domain.getTableName(), null, domain.getContentValues().get());

		if (id == -1) {
			throw new TimeCardException(this.context.getString(R.string.nothingWasCreated));
		}

		domain.setId(id);

		T inserted = this.getById(domain);
		database.close();

		return inserted;
	}

	public T update(T domain) throws TimeCardException {

		SQLiteDatabase database = this.dbHelper.getWritableDatabase();
		long rows = database.update(domain.getTableName(), domain.getContentValues().get(), "id = ?",
				new String[] { "" + domain.getId() });

		if (rows == 0) {
			throw new TimeCardException(this.context.getString(R.string.nothingWasUpdated));
		}

		T updated = this.getById(domain);
		database.close();

		return updated;
	}

	public int delete(T domain) throws TimeCardException {

		SQLiteDatabase database = this.dbHelper.getWritableDatabase();
		int deleted = database.delete(domain.getTableName(), "id = " + domain.getId(), null);
		database.close();

		if (deleted == 0) {
			throw new TimeCardException(this.context.getString(R.string.nothingWasRemoved));
		}

		return deleted;
	}

	public List<T> execute(String query) throws Exception {
		return this.execute(query, new String[] {});
	}
	
	public List<T> execute(String query, String... parameters) throws Exception {

		SQLiteDatabase database = this.dbHelper.getReadableDatabase();
		Cursor cursor = database.rawQuery(query, parameters);

		List<T> result = this.createListResult(cursor);
		database.close();

		return result;
	}

	public T executeUniqueResult(String query) throws Exception {
		return this.executeUniqueResult(query, new String[] {});
	}
	
	public T executeUniqueResult(String query, String... parameters) throws Exception {

		SQLiteDatabase database = this.dbHelper.getReadableDatabase();

		Cursor cursor = database.rawQuery(query, parameters);
		cursor.moveToFirst();
		T domain = this.cursorToDomain(cursor);
		cursor.close();

		database.close();

		return domain;
	}

	protected List<T> createListResult(Cursor cursor) throws Exception {

		List<T> objects = new ArrayList<T>();

		cursor.moveToFirst();
		while (!cursor.isAfterLast()) {

			T domain = this.cursorToDomain(cursor);
			objects.add(domain);

			cursor.moveToNext();
		}
		cursor.close();

		return objects;
	}
}